﻿// -----------------------------------------------------------------------
// <copyright file="PushMessageControl.cs" company="Zen Design Corp">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Zen.BlackBerry.Pap.Control
{
	using System;
	using System.Collections.Generic;
	using System.Xml;
	using System.Xml.Serialization;
	using Zen.BlackBerry.Common;

	/// <summary>
	/// Represents the Push PAP request message control (XML).
	/// </summary>
	public class PushMessageControl : PapControl, IXmlSerializable
	{
		private DateTime? _deliverBefore;
		private AddressList _addresses;

		/// <summary>
		/// Initializes a new instance of the <see cref="PushMessageControl"/> class.
		/// </summary>
		/// <param name="isUsingPublicPush">
		/// set to <c>true</c> if using public (BIS) push;
		/// otherwise, set to <c>false</c> if using enterprise (BES) push.
		/// </param>
		public PushMessageControl(bool isUsingPublicPush)
		{
			IsUsingPublicPush = isUsingPublicPush;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="PushMessageControl"/> class.
		/// </summary>
		/// <param name="isUsingPublicPush">
		/// set to <c>true</c> if using public (BIS) push;
		/// otherwise, set to <c>false</c> if using enterprise (BES) push.
		/// </param>
		/// <param name="idGenerator">The push-id generator.</param>
		/// <param name="userName">The unique id of the Push Initiator.</param>
		/// <remarks>
		/// The address list is initialised as PushAll to push the message to
		/// all subscribers.
		/// </remarks>
		public PushMessageControl(
			bool isUsingPublicPush, IIdGenerator idGenerator, string userName)
		{
			IsUsingPublicPush = isUsingPublicPush;
			PushId = idGenerator.GenerateId();
			UserName = userName;
			QualityOfService = DeliveryMethod.Unconfirmed;
			_addresses = new AddressList(true);
			_addresses.IsUsingPublicPush = IsUsingPublicPush;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="PushMessageControl"/> class.
		/// </summary>
		/// <param name="isUsingPublicPush">
		/// set to <c>true</c> if using public (BIS) push;
		/// otherwise, set to <c>false</c> if using enterprise (BES) push.
		/// </param>
		/// <param name="idGenerator">The push-id generator.</param>
		/// <param name="userName">The unique id of the Push Initiator.</param>
		/// <param name="addresses">The addresses.</param>
		public PushMessageControl(
			bool isUsingPublicPush,
			IIdGenerator idGenerator,
			string userName,
			IEnumerable<string> addresses)
			: this(isUsingPublicPush, idGenerator, userName)
		{
			_addresses = new AddressList();
			_addresses.IsUsingPublicPush = isUsingPublicPush;
			_addresses.AddRange(addresses);
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="PushMessageControl"/> class.
		/// </summary>
		/// <param name="isUsingPublicPush">
		/// set to <c>true</c> if using public (BIS) push;
		/// otherwise, set to <c>false</c> if using enterprise (BES) push.
		/// </param>
		/// <param name="idGenerator">The push-id generator.</param>
		/// <param name="userName">The unique id of the Push Initiator.</param>
		/// <param name="ppgNotifyRequestedTo">The PPG notify requested to.</param>
		public PushMessageControl(
			bool isUsingPublicPush,
			IIdGenerator idGenerator,
			string userName,
			string ppgNotifyRequestedTo)
			: this(isUsingPublicPush, idGenerator, userName)
		{
			PpgNotifyRequestTo = ppgNotifyRequestedTo;
			QualityOfService = DeliveryMethod.Confirmed;
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="PushMessageControl"/> class.
		/// </summary>
		/// <param name="isUsingPublicPush">
		/// set to <c>true</c> if using public (BIS) push;
		/// otherwise, set to <c>false</c> if using enterprise (BES) push.
		/// </param>
		/// <param name="idGenerator">The push-id generator.</param>
		/// <param name="userName">The unique id of the Push Initiator.</param>
		/// <param name="ppgNotifyRequestedTo">The PPG notify requested to.</param>
		/// <param name="addresses">The addresses.</param>
		public PushMessageControl(bool isUsingPublicPush, IIdGenerator idGenerator, string userName, string ppgNotifyRequestedTo, IEnumerable<string> addresses)
			: this(isUsingPublicPush, idGenerator, userName, addresses)
		{
			PpgNotifyRequestTo = ppgNotifyRequestedTo;
			QualityOfService = DeliveryMethod.Confirmed;
		}

		/// <summary>
		/// Gets or sets the push id.
		/// </summary>
		/// <value>The push id.</value>
		public string PushId
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the name of the user.
		/// </summary>
		/// <value>The name of the user.</value>
		public string UserName
		{
			get;
			set;
		}

		/// <summary>
		/// Gets the default deliver before.
		/// </summary>
		/// <value>The default deliver before.</value>
		public TimeSpan DefaultDeliverBefore
		{
			get
			{
				return PushProperties.DefaultDeliverBefore;
			}
		}

		/// <summary>
		/// Gets or sets the deliver before.
		/// </summary>
		/// <value>The deliver before.</value>
		public DateTime DeliverBefore
		{
			get
			{
				if (_deliverBefore == null)
				{
					return DateTime.UtcNow + DefaultDeliverBefore;
				}
				return _deliverBefore.Value;
			}
			set
			{
				_deliverBefore = value;
			}
		}

		/// <summary>
		/// Gets or sets the PPG notify request to.
		/// </summary>
		/// <value>The PPG notify request to.</value>
		public string PpgNotifyRequestTo
		{
			get;
			set;
		}

		/// <summary>
		/// Gets or sets the quality of service.
		/// </summary>
		/// <value>The quality of service.</value>
		public DeliveryMethod QualityOfService
		{
			get;
			set;
		}

		/// <summary>
		/// Gets the addresses.
		/// </summary>
		/// <value>The addresses.</value>
		public AddressList Addresses
		{
			get
			{
				if (_addresses == null)
				{
					_addresses = new AddressList();
					_addresses.IsUsingPublicPush = IsUsingPublicPush;
				}
				return _addresses;
			}
		}

		#region IXmlSerializable Members

		/// <summary>
		/// This method is reserved and should not be used. When implementing the IXmlSerializable interface, you should return null (Nothing in Visual Basic) from this method, and instead, if specifying a custom schema is required, apply the <see cref="T:System.Xml.Serialization.XmlSchemaProviderAttribute"/> to the class.
		/// </summary>
		/// <returns>
		/// An <see cref="T:System.Xml.Schema.XmlSchema"/> that describes the XML representation of the object that is produced by the <see cref="M:System.Xml.Serialization.IXmlSerializable.WriteXml(System.Xml.XmlWriter)"/> method and consumed by the <see cref="M:System.Xml.Serialization.IXmlSerializable.ReadXml(System.Xml.XmlReader)"/> method.
		/// </returns>
		public System.Xml.Schema.XmlSchema GetSchema()
		{
			return null;
		}

		/// <summary>
		/// Generates an object from its XML representation.
		/// </summary>
		/// <param name="reader">The <see cref="T:System.Xml.XmlReader"/> stream from which the object is deserialized.</param>
		public void ReadXml(XmlReader reader)
		{
			throw new NotImplementedException();
		}

		/// <summary>
		/// Converts an object into its XML representation.
		/// </summary>
		/// <param name="writer">The <see cref="T:System.Xml.XmlWriter"/> stream to which the object is serialized.</param>
		public void WriteXml(XmlWriter writer)
		{
			writer.WriteAttributeString("push-id", PushId);
			if (!string.IsNullOrEmpty(UserName))
			{
				writer.WriteAttributeString("source-reference", UserName);
			}
			writer.WriteRimTime("deliver-before-timestamp", DeliverBefore);

			// TODO: Deliver after timestamp should be retrieved from app settings

			if (!string.IsNullOrEmpty(PpgNotifyRequestTo))
			{
				writer.WriteAttributeString("ppg-notify-request-to", PpgNotifyRequestTo);
			}

			// Now write out the list of addresses
			Addresses.WriteXml(writer);

			writer.WriteStartElement("quality-of-service");
			writer.WriteEnum<DeliveryMethod>("delivery-method", QualityOfService);
			writer.WriteEndElement();
		}

		#endregion
	}
}
